home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / TPTUTR0F.ZIP / PASCAL13.TXT < prev    next >
Text File  |  1996-01-31  |  12KB  |  350 lines

  1.                         Turbo Pascal for DOS Tutorial
  2.                              by Glenn Grotzinger
  3.           Part 13: Recursion; system unit commands not covered yet.
  4.                  copyright(c) 1995-96 by Glenn Grotzinger
  5.  
  6. There were 2 simple problems presented...The first one...
  7.  
  8. program part12_1;
  9.  
  10.   const
  11.     maxstacksize = 500;
  12.  
  13.   type
  14.     stack = record
  15.       elements: array[1..maxstacksize] of char;
  16.       capacity: byte;
  17.     end;
  18.  
  19.   var
  20.     thestack: stack;
  21.     i: byte;
  22.     ch: char;
  23.  
  24.   procedure startstack(var thestack: stack);
  25.     begin
  26.       with thestack do
  27.         capacity := 0;
  28.     end;
  29.  
  30.   procedure place(var thestack: stack; element: char);
  31.     begin
  32.       with thestack do
  33.         begin
  34.           if capacity = maxstacksize then
  35.             writeln('**ERROR**  Trying to place element on full stack!')
  36.           else
  37.             begin
  38.               inc(capacity);
  39.               elements[capacity] := element;
  40.             end;
  41.         end;
  42.     end;
  43.  
  44.   procedure remove(var thestack: stack; var element: char);
  45.     begin
  46.       with thestack do
  47.         begin
  48.           if capacity = 0 then
  49.             writeln('**ERROR**  Trying to remove element from empty stack!')
  50.           else
  51.             begin
  52.               element := elements[capacity];
  53.               dec(capacity);
  54.             end;
  55.         end;
  56.     end;
  57.  
  58.  begin
  59.    randomize;
  60.    startstack(thestack);
  61.    write('Enter a string: ');
  62.    while ch <> #10 do
  63.      begin
  64.        read(ch);
  65.        place(thestack, ch);
  66.      end;
  67.    writeln;
  68.    writeln;
  69.    write('The string reversed is: ');
  70.    while thestack.capacity <> 0 do
  71.      begin
  72.        remove(thestack, ch);
  73.        write(ch);
  74.      end;
  75.  end.
  76. And now the second one...
  77.  
  78. program part12_2; uses crt;
  79.  
  80.   const
  81.     maxqueuesize = 50;
  82.  
  83.   type
  84.     queue = record
  85.       elements: array[1..maxqueuesize] of integer;
  86.       front, back: integer;
  87.       count: integer;
  88.     end;
  89.  
  90.   procedure startqueue(var thequeue: queue);
  91.     begin
  92.       with thequeue do
  93.         begin
  94.           front := 1;
  95.           back := maxqueuesize;
  96.           count := 0;
  97.         end;
  98.     end;
  99.  
  100.   procedure incqueue(var thenum: integer);
  101.     begin
  102.       if thenum = maxqueuesize then
  103.         thenum := 1
  104.       else
  105.         inc(thenum);
  106.     end;
  107.  
  108.   procedure place(var thequeue: queue; element: integer);
  109.     begin
  110.       with thequeue do
  111.         if count = maxqueuesize then
  112.           writeln('**ERROR** Trying to place element in full queue.')
  113.         else
  114.           begin
  115.             elements[back] := element;
  116.             incqueue(back);
  117.             inc(count);
  118.           end;
  119.     end;
  120.  
  121.   procedure remove(var thequeue: queue; var element: integer);
  122.     begin
  123.       with thequeue do
  124.         if count = 0 then
  125.           writeln('**ERROR** Trying to remove element from empty queue.')
  126.         else
  127.           begin
  128.             element := elements[front];
  129.             incqueue(front);
  130.             dec(count);
  131.           end;
  132.     end;
  133.  
  134.   var
  135.     thequeue: queue;
  136.     int, count: integer;
  137.  
  138.   begin
  139.     randomize;
  140.     startqueue(thequeue);
  141.     clrscr;
  142.     while thequeue.count <> maxqueuesize do
  143.       begin
  144.         int := random(1000) + 1;
  145.         if int <= 50 then
  146.           place(thequeue, int);
  147.         inc(count);
  148.       end;
  149.     while thequeue.count <> 0 do
  150.       begin
  151.         remove(thequeue, int);
  152.         write(int, ' ');
  153.         if thequeue.count mod 10 = 0 then
  154.           writeln;
  155.       end;
  156.  
  157.     writeln(count, ' numbers generated from 1-1000 to get these 50 ',
  158.                    'numbers from 1-50');
  159.   end.
  160.  
  161. Forward
  162. =======
  163. Very useful to defeat the fact with the compiler that a function has to be
  164. defined above another function in order to use the first function in that
  165. second function.  Above the function that it needs to be in, say something
  166. like:
  167.  
  168. function a(var input: integer): string; forward;
  169.  
  170. Then on down below in the code, you need to go ahead and define the
  171. procedure or function entirely, with code.  For the header, you would
  172. use something like this:
  173.  
  174. function a;
  175.  
  176. Doing this would accomplish being able to use a function defined after
  177. a code call of the function for some purpose.  Successive recursion using
  178. two seperate functions (a calls b; b calls a; and so on and so forth),
  179. would be one example of having to use a forward.
  180.  
  181. The $M compiler directive
  182. =========================
  183. I described the $M compiler directive back in part 8.  Please review it
  184. there.  Basically, the first number of the compiler directive is the
  185. program stack size.  It is very important.  The default, if the $M is not
  186. defined is 16K.  The maximum it can be defined to is 64K.  You may have to
  187. use this compiler directive to increase the stack size so a recursion may
  188. complete.  If the stack is filled, a runtime 202 error occurs.
  189.  
  190. Recursion
  191. =========
  192. Recursion, to put it simply, is the execution of a function or procedure
  193. directly within that same function or procedure.  It is hard, sometimes,
  194. logically to see use of recursion, but when you see a thoroughly repetitive
  195. action, recursion could be used.
  196.  
  197. Recursion should be used with a procedure which basically has a small
  198. number or NO parameters, since the recursion places a new occurrence of
  199. the procedure on the stack, along with those variables.  It is quite
  200. possible for a procedure to recurse itself upwards of thousands of times.
  201. Therefore, you could easily run out of memory in the stack in running your
  202. program.
  203.  
  204. Basically, in logic, recursion is the repetition of a procedure as a regular
  205. or irregular loop by calling the procedure inside of the procedure, with
  206. some regulated terminating code.
  207.  
  208. NOTE: Recursion must be done with relative caution in Pascal.  It is
  209. really, REALLY easy to shoot oneself in the foot, literally, by use
  210. of recursion.  It has it's advantages, but since Pascal is unlimited
  211. by how, and why you use recursion, versus other languages, which may
  212. limit it or not allow it all together.
  213.  
  214. As an example, we will look at taking a factorial of a number.  Basically,
  215. to use an example, 4! (factorial) is 4 X 3 X 2 X 1.  Algebraically, we
  216. could see a factorial (n!) as n X (n-1) X (n-2) X (n-3)...(n - (n+1)).
  217. Let's try looking at a code example that does it...after that, I will
  218. explain the process in detail that goes behind how it works.  It's a
  219. simple, elegant one line set of code in a function that does all the
  220. multiplications for any number we put in there.
  221.  
  222. I will try my best to explain what exactly is going on here in this
  223. example of recursion.  That, I find, is the hardest thing to see in
  224. the concept of how recursion works, is because it is hard to
  225. conceptualize how the variables and functions work, in a manner that
  226. is understandable.
  227.  
  228. In all of the books I have read, I have not seen an adequate description
  229. of the actual logic and action of recursion -- enough to allow people to
  230. understand the idea of what is going on.  Most teachers I've heard of and
  231. talked to, just say what I have already said to this point, and shy away
  232. from actually requiring written code using recursion, or explaining code
  233. using recursion to enable people to truly understand what is going on.
  234.  
  235. I seek to change those observed facts, by trying to fully explain this
  236. example below, so people may be able to understand them sufficiently.
  237. I hope this explanation could be the best people have ever seen, and
  238. I *definitely* want e-mail and feedback on how well I do in explaining
  239. the concepts of what is going on (via showing all variable changes at
  240. all points, and order of execution of the code), because it is one of
  241. the hardest concepts in programming that I have come across in
  242. understanding.  (I will also ask for input like this in the part I write
  243. later on readdressing pointers)
  244.  
  245. program example_of_recursion;
  246.  
  247.   function factorial(a: longint): longint;
  248.     var
  249.       c: longint;
  250.     begin
  251. {1}   c := 1;  
  252. {2}   if a > 1 then {
  253. {3}     c := a * factorial(a-1);
  254. {4}   factorial := c;
  255.     end;
  256.  
  257.   begin
  258.     writeln(factorial(4));
  259.   end.
  260. to explain the path of logic in this program in calling the function
  261. factorial with regard to the variables, the biggest problem, I think,
  262. with understanding recursion -- if you don't understand the main body
  263. of the program, something is definitely wrong with you! :>  Line #'s
  264. are placed in {}'s above this paragraph, and below this paragraph.
  265.  
  266.    { call to factorial }
  267.    {1} a = 4             c = 1
  268.    {2} 4 > 1 = true
  269.    {3} c = 4 * factorial(3);
  270.       { call to factorial }
  271.       {1} a = 3             c = 1
  272.       {2} 3 > 1 = true
  273.       {3} c = 3 * factorial(2);
  274.          { call to factorial }
  275.          {1} a = 2             c = 1
  276.          {2} 2 > 1 = true
  277.          {3} c = 2 * factorial(1);
  278.             { call to factorial }
  279.             {1} a = 1             c = 1
  280.             {2} 1 > 1 = false (so the chain of calls ends...)
  281.             {3} skipped because 2 is false.
  282.             {4} c = 1; factorial function is 1.
  283.             { end call to factorial }
  284.          {4} c = (2 * 1) = 2; factorial function is 2.
  285.          { end call to factorial }
  286.       {4} c = (3 * 2) = 6; factorial function is 6.
  287.       { end call to factorial }
  288.    {4} c = (4 * 6) = 24; factorial function is 24.
  289.    { **FINAL** termination of factorial -- return of value 24 }
  290.  
  291. If you check the code, the final value is correct.  4! = 24.  Basically,
  292. with the layout I used, you can see especially also, why memory (stack
  293. space allocated for procedure and functions specifically) runs out
  294. quick, and why I say to keep the parameters and local variables for that
  295. matter to a minimum....
  296.  
  297. Recursion can be used in procedures, as well as functions, for any
  298. repetitive action.  They are just like the function call above, which
  299. recursed when or until an action became true.
  300.  
  301. To be able to extend for example, the part 8 dir clone to list and search
  302. for files (list all files in all dirs), we would need to add another
  303. boolean variable to get permission to run through all dirs encountered.
  304. We can re-call the directory list procedure with a regulating if variable
  305. of it being a directory.
  306.  
  307. For more practice (I won't post the solution for these ones), you may wish
  308. to do this.  As another practice, you may wish to try and recode an integer
  309. power function (the "simplistic" power function) that I included in my
  310. solution to part 7's programming problem to use recursion.
  311.  
  312. Practice Programming Problem #13
  313. ================================
  314. Code a program in Pascal and entirely Pascal that will make a catalog of
  315. the additive size of all files in all dirs on a drive specified on the
  316. command-line to a text file named FILESLST.TXT.
  317.  
  318. Sample output
  319. -------------
  320. c:\>sizelist c:
  321.  
  322. Drive: C
  323. C:                       131,123
  324. C:\DOS                 5,231,131
  325. ...                     ...
  326. C:\UTIL                3,212,985
  327. C:\UTIL\ACAD             131,123
  328.                    =============
  329.                      527,212,122
  330.  
  331. Notes:
  332. 1) The additive end of the listing (under the ='s) is the total size of
  333. the files on the drive.  You may use the function offered by the DOS
  334. unit to check yourself in your addition.
  335. 2) The spacing is not exact above.  Make it look SIMILIAR to what I have
  336. above, but make it reasonably attractive...
  337. 3) Use a forward.
  338. 4) Be sure to check to be sure the drive is specified EXACTLY like above.
  339. 5) Please use recursion for going through the drive (actually, recursion
  340. is probably the best way to do this).  But, be sure you put the directories
  341. in the order listed above.
  342. 6) Sizes of subdirectories are not counted in the size of a main directory.
  343. 7) Be sure to error-check the command-line.
  344.  
  345. Next Time
  346. =========
  347. We will discuss the functions of the CRT unit.  Be sure to write comments,
  348. encouragements, problems, errors, to ggrotz@2sprint.net.
  349.  
  350.